import java.util.LinkedList;

public class GenericSearch {

	Problem myProblem;
	SearchStrategy usedStrategy;

	public GenericSearch(Problem myProblem, SearchStrategy myStrategy) {
		super();
		this.myProblem = myProblem;
		this.usedStrategy = myStrategy;
	}

	public Problem getMyProblem() {
		return myProblem;
	}

	public void setMyProblem(Problem myProblem) {
		this.myProblem = myProblem;
	}

	public SearchStrategy getMyStrategy() {
		return usedStrategy;
	}

	public void setMyStrategy(SearchStrategy myStrategy) {
		this.usedStrategy = myStrategy;
	}

	public Node gnSearch() {
		
		LinkedList<Node> newNodes = new LinkedList<Node>();
		
		// list of nodes that are to be explored
		LinkedList<Node> visitedNodes = new LinkedList<Node>();

		// defining the parameters of the root node
		Node parent = null;
		LinkedList<Node> children = new LinkedList<Node>();
		State currentState = getMyProblem().getInitialState();
		String currentMovement = ""; // operator used
		LinkedList<String> movementsSoFar = new LinkedList<String>();
		int currentLevel = 0;
		Block blocktoBeMoved =null;

		// initialize the root
		Node root = new Node(parent, children, movementsSoFar, currentLevel,
				currentMovement, currentState, blocktoBeMoved);
		
		// adding the root in the to be explored List
		visitedNodes.add(root);
		
		Node exploredNode;
	
		do
		{
			if(visitedNodes.isEmpty())
				{
					return null;
				}
			exploredNode =visitedNodes.pop();
			 printing(exploredNode);

			if(exploredNode.getBlocktoBeMoved()!= null && exploredNode.isGoal(exploredNode)) 
			{
				return exploredNode ;
			}
			
			newNodes = getMyStrategy().search(visitedNodes, exploredNode);
			
			visitedNodes = addListToList(visitedNodes,newNodes);
		}while(!visitedNodes.isEmpty() && visitedNodes.getLast().getLevel()< 10);

		return null;
	}
	
	public LinkedList<Node> addListToList(LinkedList<Node>visitedNodes ,LinkedList<Node> newNodes )
	{
		int size = newNodes.size();
		for (int i=0; i< size ;i++)
		{
			visitedNodes.addLast(newNodes.pop());
		}
		return visitedNodes;
		
	}

	public void printing(Node exploredNode )
	{
		System.out.println("In the Node : "+exploredNode.getLevel());
		if(exploredNode.getBlocktoBeMoved()!= null)
		{
		System.out.println("              Block Number :" + exploredNode.getBlocktoBeMoved().getBlockNumber());
		System.out.println("                    State  :" + exploredNode.getBlocktoBeMoved().getState());
		 printLocation(exploredNode);
		 System.out.println("");
		}
		
		printMovementsSoFar(exploredNode);
	}
	
	public void printMovementsSoFar(Node exploredNode)
	{
		LinkedList<String> seq = exploredNode.getMovementsSoFar();
		System.out.print("Movements so far:  ");
		while(!seq.isEmpty())
		{
			System.out.print(seq.pop() +" , ");
		}
		System.out.println("");
	}
	
	public void printLocation(Node exploredNode)
	{
		LinkedList<Pair> t = exploredNode.getBlocktoBeMoved().getLocation();
		System.out.print("  location: ");
		
		while(!t.isEmpty())
		{
			Pair p = t.pop();
			System.out.print("("+p.getX()+","+p.getY()+") , ");
		}
	}
}
